﻿#include <stdbool.h>
#include "pktbuf.h"
#include "mblock.h"
#include "sys_plat.h"
#include "tools.h"

static pktblk_t block_buffer[PKTBUF_BLK_CNT];  // 用于存放数据块
static pktbuf_t pktbuf_buffer[PKTBUF_BUF_CNT]; // 用于存放数据包
static mblock_t pktblk_manager;                // 用于管理数据块内存的内存管理器
static mblock_t pktbuf_manager;                // 用于管理数据包内存的内存管理器
static nlocker_t locker;

/**
 * @brief 获取当前数据块的下一个数据块
 */
static inline pktblk_t *pktblk_next(pktblk_t *blk)
{
    nlist_node_t *next_node = nlist_node_next(&blk->node);
    if (!next_node)
    {
        return NULL;
    }
    pktblk_t *next_blk = nlist_entry(pktblk_t, node, next_node);
    return next_blk;
}

/**
 * @brief 获取当前数据包的第一个数据块
 */
static inline pktblk_t *pktbuf_first_blk(const pktbuf_t *buf)
{
    return nlist_entry(pktblk_t, node, buf->block_list.first);
}

/**
 * @brief 获取数据包的起始地址
 */
uint8_t *pktbuf_data(pktbuf_t *buf)
{
    pktblk_t *blk = pktbuf_first_blk(buf);
    return blk ? blk->data : (uint8_t *)0;
}

/**
 * @brief 获得数据包的最后一个数据块
 */
static inline pktblk_t *pktbuf_last_blk(const pktbuf_t *buf)
{
    return nlist_entry(pktblk_t, node, buf->block_list.last);
}

/**
 * @brief 这里只是单纯的释放数据块
 */
static inline void pktblk_free_blk(pktblk_t *blk)
{
    mblock_free(&pktblk_manager, blk);
}

/**
 * @brief 释放数据块链表
 * @param blk_first 数据块链表的第一个数据块
 */
static void pktblk_free_list(pktblk_t *first_blk)
{
    while (first_blk)
    {
        pktblk_t *next_blk = pktblk_next(first_blk);
        pktblk_free_blk(first_blk);
        first_blk = next_blk;
    }
}

/**
 * @brief 获取指定数据块的末尾空闲内存大小
 */
static inline u_int pktblk_tail_free_size(const pktblk_t *blk)
{
    return (u_int)((blk->payload + PKTBUF_BLK_SIZE) - (blk->data + blk->size));
}

#if DBG_DISP_ENABLED(DBG_PKTBUF_LEVEL)
/**
 * @brief 打印分配的内存等相关信息
 */
static void display_check_buf(const pktbuf_t *buf)
{
    if (!buf)
    {
        DBG_ERROR(DBG_PKTBUF_LEVEL, "invalid buf in display check buf");
        return;
    }
    plat_printf("check buf: %p, size: %d\n", buf, buf->total_size);
    int index = 0;
    int total_size = 0;
    for (pktblk_t *curr_blk = pktbuf_first_blk(buf); curr_blk; curr_blk = pktblk_next(curr_blk))
    {
        DBG_ASSERT(curr_blk->data >= curr_blk->payload);
        DBG_ASSERT(curr_blk->data <= curr_blk->payload + PKTBUF_BLK_SIZE);

        plat_printf("index: %d, ", index++);
        u_int pre_size = (int)(curr_blk->data - curr_blk->payload);
        u_int used_size = curr_blk->size;
        u_int free_size = pktblk_tail_free_size(curr_blk);
        plat_printf("pre_size: %d, used_size: %d, tail_size: %d\n", pre_size, used_size, free_size);
        int blk_total_size = pre_size + used_size + free_size;
        DBG_ASSERT(blk_total_size == PKTBUF_BLK_SIZE);
        total_size += used_size;
    }

    if (total_size != buf->total_size)
    {
        DBG_ERROR(DBG_PKTBUF_LEVEL, "total_size != buf->total_size, total_size = %d, buf->total_size = %d", total_size, buf->total_size);
        return;
    }
}
#else
#define display_check_buf(buf) \
    {                          \
    }
#endif

/**
 * @brief 数据包和数据块相关存储结构初始化
 */
net_err_t pktbuf_init()
{
    DBG_INFO(DBG_PKTBUF_LEVEL, "pkt buf init begin!");

    // 初始化锁
    if (nlocker_init(&locker, NLOCKER_THREAD) < NET_ERR_OK)
    {
        DBG_ERROR(DBG_PKTBUF_LEVEL, "locker init failed in pktbuf init!");
        return NET_ERR_SYS;
    }

    // 初始化内存管理器
    if (mblock_init(&pktblk_manager, block_buffer, sizeof(pktblk_t), PKTBUF_BLK_CNT, PKTBUF_LOCKER) < NET_ERR_OK)
    {
        DBG_ERROR(DBG_PKTBUF_LEVEL, "mblock init failed in block init!");
        nlocker_destroy(&locker);
        return NET_ERR_SYS;
    }

    if (mblock_init(&pktbuf_manager, pktbuf_buffer, sizeof(pktbuf_t), PKTBUF_BUF_CNT, PKTBUF_LOCKER) < NET_ERR_OK)
    {
        DBG_ERROR(DBG_PKTBUF_LEVEL, "mblock init failed in block init!");
        nlocker_destroy(&locker);
        mblock_destroy(&pktblk_manager);
        return NET_ERR_SYS;
    }

    DBG_INFO(DBG_PKTBUF_LEVEL, "pkt buf init done!");
    return NET_ERR_OK;
}

/**
 * @brief 分配数据块内存
 */
static inline pktblk_t *pktblk_alloc(int tmo)
{
    pktblk_t *alloc_pktblk = mblock_alloc(&pktblk_manager, tmo);
    return alloc_pktblk;
}

/**
 * @brief 用指定的插入方式建立指定大小的数据块链表
 * @param size 数据包的大小
 * @param add_front 是否进行头插，不头插则进行尾插
 * @return 建立好的数据块链表的首地址
 */
static pktblk_t *pktblk_alloc_list(int size, bool add_front)
{
    pktblk_t *first_blk = NULL; // 指向链表的第一个数据块
    pktblk_t *pre_blk = NULL;   // 指向链表的上一个插入的数据块

    while (size)
    {
        pktblk_t *alloc_pktblk = pktblk_alloc(DELIVER_NO_WAITTIME);
        if (!alloc_pktblk)
        {
            DBG_ERROR(DBG_PKTBUF_LEVEL, "no free pkt block now!");
            pktblk_free_list(first_blk);
            return NULL;
        }
        nlist_node_init(&alloc_pktblk->node);
        int curr_size = size > PKTBUF_BLK_SIZE ? PKTBUF_BLK_SIZE : size;
        size = size - curr_size;
        alloc_pktblk->size = curr_size;

        if (add_front)
        {
            // 头插法
            alloc_pktblk->data = alloc_pktblk->payload + (PKTBUF_BLK_SIZE - curr_size);

            if (first_blk)
            {
                nlist_node_set_next(&alloc_pktblk->node, &first_blk->node);
            }
            first_blk = pre_blk = alloc_pktblk;
        }
        else
        {
            // 尾插法
            alloc_pktblk->data = alloc_pktblk->payload;
            // 第一个数据块
            if (!first_blk)
            {
                first_blk = alloc_pktblk;
            }
            if (pre_blk)
            {
                nlist_node_set_next(&pre_blk->node, &alloc_pktblk->node);
            }
            pre_blk = alloc_pktblk;
        }
    }

    return first_blk;
}

/**
 * @brief 向指定的数据包中以指定的方式插入指定的数据块链表
 * @param buf 指定的数据包
 * @param first_blk 数据块链表的第一个节点
 * @param add_front 是否以头插法进行插入，否则以尾插法进行插入
 */
static void pktbuf_insert_blk_list(pktbuf_t *buf, pktblk_t *first_blk, bool add_front)
{
    if (add_front)
    {
        // 头插法
        pktblk_t *curr_blk = first_blk;
        pktblk_t *pre_blk = NULL; // 上一次被插入的数据块
        while (curr_blk)
        {
            pktblk_t *next_blk = pktblk_next(curr_blk);
            if (!pre_blk)
            {
                nlist_insert_first(&buf->block_list, &curr_blk->node);
            }
            else
            {
                nlist_insert_after(&buf->block_list, &pre_blk->node, &curr_blk->node);
            }
            buf->total_size += curr_blk->size;
            pre_blk = curr_blk;
            curr_blk = next_blk;
        }
    }
    else
    {
        // 尾插法
        pktblk_t *curr_blk = first_blk;
        while (curr_blk)
        {
            pktblk_t *next_blk = pktblk_next(curr_blk);
            nlist_insert_last(&buf->block_list, &curr_blk->node);
            buf->total_size += curr_blk->size;
            curr_blk = next_blk;
        }
    }
}

/**
 * @brief 分配指定大小的数据包
 * @param size 数据包的大小
 * @return 分配的数据包地址
 */
pktbuf_t *pktbuf_alloc(u_int size)
{
    pktbuf_t *pktbuf = mblock_alloc(&pktbuf_manager, DELIVER_NO_WAITTIME);
    if (!pktbuf)
    {
        DBG_ERROR(DBG_PKTBUF_LEVEL, "no free pkt buf now!");
        return NULL;
    }
    pktbuf->ref = 1;
    pktbuf->total_size = 0;
    nlist_init(&pktbuf->block_list);
    nlist_node_init(&pktbuf->node);

    if (size)
    {
        pktblk_t *pktblk = pktblk_alloc_list(size, true);
        if (!pktblk)
        {
            mblock_free(&pktbuf_manager, pktbuf);
            return NULL;
        }

        pktbuf_insert_blk_list(pktbuf, pktblk, true);
    }

    pktbuf_reset_acc(pktbuf);
    display_check_buf(pktbuf);

    return pktbuf;
}

/**
 * @brief 释放数据包内存
 */
void pktbuf_free(pktbuf_t *buf)
{
    if (buf)
    {
        nlocker_lock(&locker);
        if (!(--buf->ref))
        {
            pktblk_free_list(pktbuf_first_blk(buf));
            mblock_free(&pktbuf_manager, buf);
        }
        nlocker_unlock(&locker);
    }
}

/**
 * @brief 给数据包添加指定大小的包头
 * @param buf 指定的数据包
 * @param size 包头的大小
 * @param cont 是否以连续的空间添加包头 true:连续分配 false:不连续分配
 */
net_err_t pktbuf_add_header(pktbuf_t *buf, int size, bool cont)
{
    if (!buf)
        return NET_ERR_NULLP;

    DBG_ASSERT(buf->ref);

    pktblk_t *first_blk = pktbuf_first_blk(buf);
    // 如果空间够则直接分配
    int pre_freesize = (int)(first_blk->data - first_blk->payload);
    if (size <= pre_freesize)
    {
        first_blk->data -= size;
        first_blk->size += size;
        buf->total_size += size;
        goto end;
    }

    if (cont)
    {
        // 连续分配
        if (size > PKTBUF_BLK_SIZE)
        {
            DBG_ERROR(DBG_PKTBUF_LEVEL, "the packet header is too big, can not add cont!");
            return NET_ERR_SIZE;
        }

        pktblk_t *blk = pktblk_alloc_list(size, true);
        if (!blk)
        {
            DBG_ERROR(DBG_PKTBUF_LEVEL, "the blk is null in add header!");
            return NET_ERR_NULLP;
        }
        pktbuf_insert_blk_list(buf, blk, true);
    }
    else
    {
        // 不连续分配
        first_blk->data = first_blk->payload;
        first_blk->size += pre_freesize;
        buf->total_size += pre_freesize;
        size -= pre_freesize;
        pktblk_t *blk = pktblk_alloc_list(size, true);
        if (!blk)
        {
            DBG_ERROR(DBG_PKTBUF_LEVEL, "the blk is null in add header!");
            return NET_ERR_NULLP;
        }
        pktbuf_insert_blk_list(buf, blk, true);
    }
end:
    display_check_buf(buf);
    return NET_ERR_OK;
}

/**
 * @brief 移除数据包的包头
 * @param buf 数据包
 * @param size 包头大小
 */
net_err_t pktbuf_remove_header(pktbuf_t *buf, int size)
{
    if (!buf)
        return NET_ERR_NULLP;

    DBG_ASSERT(buf->ref);

    pktblk_t *blk = pktbuf_first_blk(buf);
    while (size)
    {
        if (size < blk->size)
        {
            blk->size -= size;
            blk->data = blk->data + size;
            buf->total_size -= size;
            break;
        }

        pktblk_t *next_blk = pktblk_next(blk);
        int curr_size = blk->size;
        nlist_remove(&buf->block_list, &blk->node);
        pktblk_free_blk(blk);
        size -= curr_size;
        buf->total_size -= curr_size;
        blk = next_blk;
    }

    display_check_buf(buf);
    return NET_ERR_OK;
}

/**
 * @brief 调整数据包的大小
 * @param buf 数据包
 * @param to_size 调整后数据包的大小
 */
net_err_t pktbuf_resize(pktbuf_t *buf, int to_size)
{
    if (!buf)
        return NET_ERR_NULLP;

    DBG_ASSERT(buf->ref);

    if (to_size == buf->total_size)
    {
        return NET_ERR_OK;
    }

    if (!buf->total_size)
    {
        // 如果数据包大小为0,则直接分配空间
        pktblk_t *first_blk = pktblk_alloc_list(to_size, false);
        if (!first_blk)
        {
            DBG_ERROR(DBG_PKTBUF_LEVEL, "alloc blk list failed in resize buf!");
            return NET_ERR_MEM;
        }
        pktbuf_insert_blk_list(buf, first_blk, false);
        return NET_ERR_OK;
    }

    if (to_size > buf->total_size)
    {
        // 对数据包进行扩大，则直接在尾部增加空间
        pktblk_t *tail_blk = pktbuf_last_blk(buf);
        int inc_size = to_size - buf->total_size;          // 需要新增的空间
        int remain_size = pktblk_tail_free_size(tail_blk); // 最后一个数据块的末尾空闲空间

        if (remain_size >= inc_size)
        {
            // 剩余的空间足够，则直接存放
            tail_blk->size += inc_size;
            buf->total_size += inc_size;
        }
        else
        {
            // 剩余的空间不够，则还需要申请新的空间
            // 先调整最后一个块
            tail_blk->size += remain_size;
            buf->total_size += remain_size;

            // 分配新的空间
            inc_size -= remain_size;
            pktblk_t *new_blk_list = pktblk_alloc_list(inc_size, false);
            if (!new_blk_list)
            {
                DBG_ERROR(DBG_PKTBUF_LEVEL, "alloc blk list failed in resize buf!");
                return NET_ERR_MEM;
            }
            pktbuf_insert_blk_list(buf, new_blk_list, false);
        }
    }
    else
    {
        // 对数据包进行缩小,则减少尾部空间
        int total_size = 0;
        pktblk_t *tail_blk = NULL;
        for (pktblk_t *curr_blk = pktbuf_first_blk(buf); curr_blk; curr_blk = pktblk_next(curr_blk))
        {
            total_size += curr_blk->size;
            if (total_size >= to_size)
            {
                tail_blk = curr_blk;
                break;
            }
        }
        if (!tail_blk)
        {
            DBG_ERROR(DBG_PKTBUF_LEVEL, "the blk list has some error in memory!");
            return NET_ERR_MEM;
        }

        pktblk_t *curr_blk = pktblk_next(tail_blk);
        int free_size = 0;
        while (curr_blk)
        {
            pktblk_t *next_blk = pktblk_next(curr_blk);
            free_size += curr_blk->size;
            nlist_remove(&buf->block_list, &curr_blk->node);
            pktblk_free_blk(curr_blk);
            curr_blk = next_blk;
        }

        tail_blk->size -= buf->total_size - to_size - free_size;
        buf->total_size = to_size;

        // 注意末尾数据块的边界条件
        if (!tail_blk->size)
        {
            nlist_remove(&buf->block_list, &tail_blk->node);
            pktblk_free_list(tail_blk);
        }
    }

    display_check_buf(buf);
    return NET_ERR_OK;
}

/**
 * @brief 合并两个包,注意的是,这里并没有考虑效率问题
 * @param dest 放在前面的包
 * @param src 放在后面的包
 */
net_err_t pktbuf_join(pktbuf_t *dest, pktbuf_t *src)
{
    if (!dest || !src)
    {
        return NET_ERR_NULLP;
    }

    DBG_ASSERT(dest->ref);
    DBG_ASSERT(src->ref);

    pktblk_t *first_blk = NULL;
    while (first_blk = pktbuf_first_blk(src))
    {
        nlist_remove_first(&src->block_list);
        pktbuf_insert_blk_list(dest, first_blk, false);
    }
    pktbuf_free(src);

    display_check_buf(dest);

    return NET_ERR_OK;
}

/**
 * @brief 将非连续的包头调整为连续的包头
 * @param buf 需要进行调整的数据包
 * @param size 包头的大小
 */
net_err_t pktbuf_set_cont(pktbuf_t *buf, int size)
{
    DBG_ASSERT(buf->ref);

    if (size > buf->total_size || size > PKTBUF_BLK_SIZE)
    {
        DBG_ERROR(DBG_PKTBUF_LEVEL, "the header size is too big than total_size or blk_size!");
        return NET_ERR_MEM;
    }

    pktblk_t *first_blk = pktbuf_first_blk(buf);
    if (size <= first_blk->size)
    {
        goto success;
    }
    // 将第一个数据块的数据拷贝到起始位置
    uint8_t *dest = first_blk->payload;
    for (int i = 0; i < first_blk->size; ++i)
    {
        *dest++ = first_blk->data[i];
    }
    first_blk->data = first_blk->payload;
    pktblk_t *curr_blk = pktblk_next(first_blk);
    int remain_size = size - first_blk->size;
    while (remain_size && curr_blk)
    {
        int curr_size = curr_blk->size > remain_size ? remain_size : curr_size;
        plat_memcpy(dest, curr_blk->data, curr_size);
        dest += curr_size;
        curr_blk->data += curr_size;
        curr_blk->size -= curr_size;
        first_blk->size += curr_size;
        remain_size -= curr_size;

        if (curr_blk->size == 0)
        {
            pktblk_t *next_blk = pktblk_next(curr_blk);
            nlist_remove(&buf->block_list, &curr_blk->node);
            pktblk_free_blk(curr_blk);
            curr_blk = next_blk;
        }
    }

success:
    display_check_buf(buf);
    return NET_ERR_OK;
}

/**
 * @brief 重置数据包的读写相关参数,类似于文件系统中的open
 * @param buf 需要进行操作的数据包
 */
net_err_t pktbuf_reset_acc(pktbuf_t *buf)
{
    if (!buf)
        return NET_ERR_PARAM;

    // DBG_ASSERT(buf->ref);
    if (buf->ref == 0)
    {
        DBG_ERROR(DBG_PKTBUF_LEVEL, "test error!");
    }

    buf->pos = 0;
    buf->curr_blk = pktbuf_first_blk(buf);
    buf->blk_offset = buf->curr_blk ? buf->curr_blk->data : (uint8_t *)0;

    return NET_ERR_OK;
}

/**
 * @brief 数据包的读写pos进行偏移，需要保证size的准确性，即只能在一个数据块内偏移
 * @param buf 指定的数据包
 * @param size 偏移的大小
 */
static void pktbuf_moveforward(pktbuf_t *buf, int size)
{
    // 这里在偏移前已经保证了size的准确性
    buf->pos += size;
    buf->blk_offset += size;
    if (buf->blk_offset >= buf->curr_blk->data + buf->curr_blk->size)
    {
        buf->curr_blk = pktblk_next(buf->curr_blk);
        if (buf->curr_blk)
        {
            buf->blk_offset = buf->curr_blk->data;
        }
        else
        {
            buf->blk_offset = (uint8_t *)0;
        }
    }
    display_check_buf(buf);
}

/**
 * @brief 向数据包中写入数据
 * @param buf 需要被写入数据的数据包
 * @param src 需要被写入的数据
 * @param size 写入数据的大小
 */
net_err_t pktbuf_write(pktbuf_t *buf, const uint8_t *src, int size)
{
    if (!buf || !src)
    {
        return NET_ERR_PARAM;
    }

    DBG_ASSERT(buf->ref);

    // 比较剩余的空间以及能够写入的空间
    int remain_size = pktbuf_total_remain(buf);
    if (size > remain_size)
    {
        DBG_ERROR(DBG_PKTBUF_LEVEL, "the write size:%d is too big than remain_size:%d", size, remain_size);
        return NET_ERR_SIZE;
    }

    while (size)
    {
        int blk_size = pktbuf_blk_remain(buf);
        int copy_size = size > blk_size ? blk_size : size;
        plat_memcpy(buf->blk_offset, src, copy_size);
        src += copy_size;
        size -= copy_size;
        pktbuf_moveforward(buf, copy_size);
    }
    return NET_ERR_OK;
}

/**
 * @brief 从数据包中读取数据
 * @param buf 需要被读取数据的数据包
 * @param dst 读取后的数据存放的位置
 * @param buf_size 读取数据的大小
 * @param dst_size dst大小
 */
net_err_t pktbuf_read(pktbuf_t *buf, uint8_t *dst, int buf_size, int dst_size)
{
    display_check_buf(buf);

    if (!buf || !dst)
    {
        return NET_ERR_PARAM;
    }

    DBG_ASSERT(buf->ref);

    // 比较剩余的空间以及能够写入的空间
    if (buf_size > dst_size)
    {
        DBG_ERROR(DBG_PKTBUF_LEVEL, "the dst size:%d shorter than buf_size:%d!", dst_size, buf_size);
        return NET_ERR_SIZE;
    }

    int remain_size = pktbuf_total_remain(buf);
    if (buf_size > remain_size)
    {
        DBG_ERROR(DBG_PKTBUF_LEVEL, "the read size:%d is too big than remain_size:%d", buf_size, buf->total_size - buf->pos);
        return NET_ERR_SIZE;
    }

    int tmp_idx = 0;
    while (buf_size)
    {
        int blk_size = pktbuf_blk_remain(buf);
        int copy_size = buf_size > blk_size ? blk_size : buf_size;
        plat_memcpy(dst, buf->blk_offset, copy_size);
        dst += copy_size;
        buf_size -= copy_size;
        pktbuf_moveforward(buf, copy_size);
    }
    return NET_ERR_OK;
}

/**
 * @brief 偏移数据包读取位置
 * @param buf 需要操作的数据包
 * @param offset 相对于头部偏移量
 */
net_err_t pktbuf_seek(pktbuf_t *buf, int offset)
{
    if (!buf)
    {
        return NET_ERR_NULLP;
    }

    DBG_ASSERT(buf->ref);

    if (offset < 0 || offset > buf->total_size)
    {
        DBG_ERROR(DBG_PKTBUF_LEVEL, "the offset:%d param is invalid and the total_size is %d!", offset, buf->total_size);
        return NET_ERR_PARAM;
    }

    int move_bytes = 0; // 实际需要偏移的字节数
    if (buf->pos > offset)
    {
        // 为了方便，直接把pos放到开头
        pktbuf_reset_acc(buf);
        move_bytes = offset;
    }
    else
    {
        move_bytes = offset - buf->pos;
    }

    while (move_bytes)
    {
        int remain_size = pktbuf_blk_remain(buf);
        int curr_move = move_bytes > remain_size ? remain_size : move_bytes;
        pktbuf_moveforward(buf, curr_move);
        move_bytes -= curr_move;
    }

    return NET_ERR_OK;
}

/**
 * @brief 将一个数据包拷贝给另一个数据包
 * @param dst 目的数据包
 * @param src 源数据包
 * @param size 被拷贝的内存大小
 */
net_err_t pktbuf_copy(pktbuf_t *dst, pktbuf_t *src, int size)
{
    DBG_ASSERT(dst->ref);
    DBG_ASSERT(src->ref);

    if (size > pktbuf_total_remain(dst) || size > pktbuf_total_remain(src))
    {
        DBG_ERROR(DBG_PKTBUF_LEVEL, "the copy size(%d) is too bigger than dst_size(%d) or src_size(%d)!", size, pktbuf_total_remain(dst), pktbuf_total_remain(src));
        return NET_ERR_PARAM;
    }

    while (size)
    {
        int dst_blk_remain = pktbuf_blk_remain(dst);
        int src_blk_remain = pktbuf_blk_remain(src);
        int copy_size = dst_blk_remain > src_blk_remain ? src_blk_remain : dst_blk_remain;
        copy_size = copy_size > size ? size : copy_size;
        plat_memcpy(dst->blk_offset, src->blk_offset, copy_size);
        pktbuf_moveforward(dst, copy_size);
        pktbuf_moveforward(src, copy_size);
        size -= copy_size;
    }

    return NET_ERR_OK;
}

/**
 * @brief 以特定的值填充数据包
 * @param buf 被填充的数据包
 * @param v 用于填充的值
 * @param size 填充的数据量
 */
net_err_t pktbuf_fill(pktbuf_t *buf, uint8_t v, int size)
{
    if (!buf)
    {
        return NET_ERR_PARAM;
    }

    DBG_ASSERT(buf->ref);

    // 比较剩余的空间以及能够写入的空间
    int remain_size = pktbuf_total_remain(buf);
    if (size > remain_size)
    {
        DBG_ERROR(DBG_PKTBUF_LEVEL, "the write size:%d is too big than remain_size:%d", size, remain_size);
        return NET_ERR_SIZE;
    }

    while (size)
    {
        int blk_size = pktbuf_blk_remain(buf);
        int copy_size = size > blk_size ? blk_size : size;
        plat_memset(buf->blk_offset, v, copy_size);
        size -= copy_size;
        pktbuf_moveforward(buf, copy_size);
    }
    return NET_ERR_OK;
}

/**
 * @brief 根据给定的包和长度按照16bit计算校验和
 * @param buf 数据包
 * @param len 需要被计算校验和的包的长度
 * @param pre_num 之前计算出来的校验和
 * @param complement 是否需要取反
 * @return 计算出的校验和
 */
uint16_t pktbuf_checksum16(pktbuf_t *buf, int len, uint32_t pre_sum, bool complement)
{
    DBG_ASSERT(buf->ref);

    // 先检查长度输入是否有误
    int remain_size = pktbuf_total_remain(buf);
    if (remain_size < len)
    {
        DBG_ERROR(DBG_PKTBUF_LEVEL, "the len input:%d is too biger than remain_size:%d!", len, remain_size);
        return 0;
    }

    uint32_t checksum = pre_sum;
    uint32_t offset = 0;
    while (len > 0)
    {
        int blk_size = pktbuf_blk_remain(buf);
        int curr_size = (len > blk_size) ? blk_size : len;
        checksum = tools_checksum16(offset, buf->blk_offset, curr_size, checksum, false);
        len -= curr_size;
        pktbuf_moveforward(buf, curr_size);
        offset += curr_size;
    }

    return complement ? (uint16_t)(~checksum) : (uint16_t)checksum;
}